import React, { useState } from "react";
import type { DragEndEvent, DragOverEvent } from "@dnd-kit/core";
import {
  DndContext,
  PointerSensor,
  useSensor,
  useSensors,
  closestCenter,
  DragOverlay,
} from "@dnd-kit/core";
import { restrictToHorizontalAxis } from "@dnd-kit/modifiers";
import {
  arrayMove,
  SortableContext,
  horizontalListSortingStrategy,
} from "@dnd-kit/sortable";
import { Table } from "antd";
import type { TableColumnsType } from "antd";
import TableHeaderCell from "./TableHeaderCell";
import TableBodyCell from "./TableBodyCell";
import { DragIndexContext, DragIndexState } from "./utils";

interface DataType {
  key: string;
  name: string;
  gender: string;
  age: number;
  email: string;
  address: string;
}

const dataSource: DataType[] = [
  {
    key: "1",
    name: "John Brown",
    gender: "male",
    age: 32,
    email: "John Brown@example.com",
    address: "London No. 1 Lake Park",
  },
  {
    key: "2",
    name: "Jim Green",
    gender: "female",
    age: 42,
    email: "jimGreen@example.com",
    address: "London No. 1 Lake Park",
  },
  {
    key: "3",
    name: "Joe Black",
    gender: "female",
    age: 32,
    email: "JoeBlack@example.com",
    address: "Sidney No. 1 Lake Park",
  },
  {
    key: "4",
    name: "George Hcc",
    gender: "male",
    age: 20,
    email: "george@example.com",
    address: "Sidney No. 1 Lake Park",
  },
];

const baseColumns: TableColumnsType<DataType> = [
  { title: "Name", dataIndex: "name" },
  { title: "Gender", dataIndex: "gender" },
  { title: "Age", dataIndex: "age" },
  { title: "Email", dataIndex: "email" },
  { title: "Address", dataIndex: "address" },
];

const App: React.FC = () => {
  const [dragIndex, setDragIndex] = useState<DragIndexState>({
    active: -1,
    over: -1,
  });

  const [columns, setColumns] = useState(() =>
    baseColumns.map((column, i) => ({
      ...column,
      key: `${i}`,
      onHeaderCell: () => ({ id: `${i}` }),
      onCell: () => ({ id: `${i}` }),
    }))
  );

  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 1,
      },
    })
  );

  const onDragEnd = ({ active, over }: DragEndEvent) => {
    if (active.id !== over?.id) {
      setColumns((prevState) => {
        const activeIndex = prevState.findIndex((i) => i.key === active.id);
        const overIndex = prevState.findIndex((i) => i.key === over?.id);
        return arrayMove(prevState, activeIndex, overIndex);
      });
    }
    setDragIndex({ active: -1, over: -1 });
  };

  const onDragOver = ({ active, over }: DragOverEvent) => {
    const activeIndex = columns.findIndex((i) => i.key === active.id);
    const overIndex = columns.findIndex((i) => i.key === over?.id);
    setDragIndex({
      active: active.id,
      over: over?.id,
      direction: overIndex > activeIndex ? "right" : "left",
    });
  };

  return (
    <DndContext
      sensors={sensors}
      modifiers={[restrictToHorizontalAxis]}
      onDragEnd={onDragEnd}
      onDragOver={onDragOver}
      collisionDetection={closestCenter}
    >
      <SortableContext
        items={columns.map((i) => i.key)}
        strategy={horizontalListSortingStrategy}
      >
        <DragIndexContext.Provider value={dragIndex}>
          <Table<DataType>
            components={{
              header: { cell: TableHeaderCell },
              body: { cell: TableBodyCell },
            }}
            rowKey="key"
            columns={columns}
            dataSource={dataSource}
          />
        </DragIndexContext.Provider>
      </SortableContext>
      <DragOverlay>
        <div style={{ backgroundColor: "gray", padding: 16 }}>
          {
            columns[columns.findIndex((i) => i.key === dragIndex.active)]
              ?.title as React.ReactNode
          }
        </div>
      </DragOverlay>
    </DndContext>
  );
};

export default App;
